<?php

use km\Cache;

use \PHPUnit_Framework_TestCase;

require_once dirname(__FILE__) . '/../lib/Km.php';
require_once dirname(__FILE__) . '/../lib/km/Cache.php';
require_once dirname(__FILE__) . '/../lib/km/cache/Buffer.php';

require_once dirname(__FILE__) . '/cache/StubCache.php';

function stub_dynamic_block_callback() {
	return 'I am dynamic';
}

class StubCallback {
	static $context;
	static function simple()
	{
		return 'I am dynamic';
	}
	static function context($arg = '')
	{
		return self::$context . $arg;
	}
}

class CacheTest extends PHPUnit_Framework_TestCase {
	/**
	 * @var Cache
	 */
	private $cache;
	
	function testPutAndGet()
	{
		$this->cache->put('test_id', 'test_value');
		$this->assertEquals('test_value', $this->cache->get('test_id'));
	}
	
	function testGetStore()
	{
		$retreiver = function () {
			return 'test_value';
		};
		$value = $this->cache->getStore('test_id', $retreiver);
		$this->assertEquals($retreiver(), $this->cache->get('test_id'));
	}
	
	function testDelete()
	{
		$this->cache->put('test_id', 'test_value');
		$this->cache->delete('test_id');
		$this->assertFalse($this->cache->get('test_id'));
	}
	
	function testTagCleanup()
	{
		$this->cache->put('test_id_1', 'test_value_1', 'test_tag');
		$this->cache->put('test_id_2', 'test_value_2', 'test_tag');
		$this->cache->cleanup('test_tag');
		$this->assertFalse($this->cache->get('test_id_1'));
		$this->assertFalse($this->cache->get('test_id_2'));
	}

	function testSimpleOutputCaching()
	{
		$buffer = "I am buffer";
		$cache = $this->cache;
		$this->cache->getBuffer('test', function() use ($cache, $buffer) {
			echo $buffer;
		});
		$this->assertEquals($buffer, $cache->getBuffer('test'));
	}

	function testOutputCachingWithDynamicBlocks()
	{
		$cache = $this->cache;
		$buffer = "I am buffer";
		$this->cache->getBuffer('test', function() use ($cache, $buffer) {
			echo $buffer;
			echo $cache->dynamicBuffer(array('StubCallback', 'simple'));
			echo $buffer;
			echo $cache->dynamicBuffer(array('StubCallback', 'context'));
			echo $buffer;
			echo $cache->dynamicBuffer(array('StubCallback', 'context'), 'argument');
			echo $buffer;
		});
		StubCallback::$context = 'ensure callbacks are called in the rendering process, not cached';
		$expectation = $buffer .
			StubCallback::simple() .
			$buffer .
			StubCallback::context() .
			$buffer .
			StubCallback::context('argument') .
			$buffer;
		$this->assertEquals($expectation, $cache->getBuffer('test'));
	}

	function testNestedOutputCaching()
	{
		$cache = $this->cache;
		$buffer = "I am buffer";
		$nestedBuffer = "I am nested buffer";
		$deeplyNestedBuffer = "I am deeply nested buffer";
		$this->cache->getBuffer('test', function() use ($cache, $buffer, $nestedBuffer, $deeplyNestedBuffer) {
			echo $buffer;
			$cache->getBuffer('nested test', function() use ($cache, $nestedBuffer, $deeplyNestedBuffer) {
				echo $nestedBuffer;
				$cache->getBuffer('deeply nested test', function() use ($cache, $deeplyNestedBuffer) {
					echo $deeplyNestedBuffer;
				});
				echo $nestedBuffer;
			});
			echo $buffer;
		});

		//$this->cache->closeBuffer();
		$this->assertEquals(
			$buffer . $nestedBuffer . $deeplyNestedBuffer . $nestedBuffer . $buffer,
			$cache->getBuffer('test')
		);
	}
	
	function setUp()
	{
		StubCache::cleanup();
		$this->cache = new Cache();
		$this->cache->setup(
			array('StubCache', 'get'), 
			array('StubCache', 'put'), 
			array('StubCache', 'delete')
		);
	}
}